﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.Infra.Core.Logging;
using System.Reflection;
using System.Net;
using System.IO;
using EL = Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;

namespace Sinacor.Infra.Service.Data
{
	public static class QueryExecutionLog
	{
		public const int LOGTYPE_QUERYEXECUTION = 5;
		static LogData _logData;

		static QueryExecutionLog()
		{
			_logData = new LogData();
			_logData.LogTimestamp = DateTime.Now;
			_logData.SourceMachine = Dns.GetHostName();
			_logData.DetailCollection = new LogDetailCollection();
		}

		/// <summary>
		/// Loga a execução de uma query sem erro(s)
		/// </summary>
		/// <param name="serviceMethodName">Nome completo do Servico(Namespace.Servico.Metodo)</param>
		/// <param name="startTime">Hora de inicio</param>
		/// <param name="finishTime">Hora de termino</param>
		/// <param name="query">Query processada</param>
		/// <param name="companyId">Usuario do banco de dados que executou a query</param>
		public static void Log(string stackTrace, DateTime startTime, DateTime finishTime, string query, int companyId)
		{
            //Removido temporariamente.
            /*
			_logData.LogType = LOGTYPE_QUERYEXECUTION;
			_logData.SourceClass = RetrieveServiceName(stackTrace);
			_logData.CompanyId = companyId;

			try
			{
				_logData.DetailCollection.Add("HoraInicio", startTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("HoraFim", finishTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("TempoExecucao", FormatTimeSpanToString(finishTime.Subtract(startTime)));
				_logData.DetailCollection.Add("Query", query);

				Sinacor.Infra.Core.Logging.Logging.Log(_logData);
			}
			catch { }
            */
		}

		/// <summary>
		/// Loga a execução de uma query sem erro(s)
		/// </summary>
		/// <param name="serviceMethodName">Nome completo do Servico(Namespace.Servico.Metodo)</param>
		/// <param name="startTime">Hora de inicio</param>
		/// <param name="finishTime">Hora de termino</param>
		/// <param name="query">Query processada</param>
		/// <param name="companyId">Usuario do banco de dados que executou a query</param>
		public static void Log(string stackTrace, DateTime startTime, DateTime finishTime, int companyId, string insertCommand, string updateCommand, string deleteCommand)
		{
            //Removido temporariamente.
            /*
			_logData.LogType = LOGTYPE_QUERYEXECUTION;
			_logData.SourceClass = RetrieveServiceName(stackTrace);
			_logData.CompanyId = companyId;

			try
			{
				_logData.DetailCollection.Add("HoraInicio", startTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("HoraFim", finishTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("TempoExecucao", FormatTimeSpanToString(finishTime.Subtract(startTime)));
				
				if(!String.IsNullOrEmpty(insertCommand))
					_logData.DetailCollection.Add("InsertCommand", insertCommand);
				if (!String.IsNullOrEmpty(insertCommand))
					_logData.DetailCollection.Add("UpdateCommand", updateCommand);
				if (!String.IsNullOrEmpty(insertCommand))
					_logData.DetailCollection.Add("DeleteCommand", deleteCommand);

				Sinacor.Infra.Core.Logging.Logging.Log(_logData);
			}
			catch { }
           */
		}

		/// <summary>
		/// Loga a execução de uma query com erro(s)
		/// </summary>
		/// <param name="serviceMethodName">Nome completo do Servico(Namespace.Servico.Metodo)</param>
		/// <param name="startTime">Hora de inicio</param>
		/// <param name="finishTime">Hora de termino</param>
		/// <param name="query">Query processada</param>
		/// <param name="errorException">Exceção tratada</param>
		/// <param name="companyId">Usuario do banco de dados que executou a query</param>
		public static void Log(string stackTrace, DateTime startTime, DateTime finishTime, string query, Exception errorException, int companyId)
		{
            //Removido temporariamente.
            /*
			_logData.LogType = LOGTYPE_QUERYEXECUTION;
			_logData.SourceClass = RetrieveServiceName(stackTrace);
			_logData.CompanyId = companyId;

			try
			{
				_logData.DetailCollection.Add("HoraInicio", startTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("HoraFim", finishTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("TempoExecucao", FormatTimeSpanToString(finishTime.Subtract(startTime)));
				_logData.DetailCollection.Add("Query", query);
				_logData.DetailCollection.Add("Exceção", FormatExceptionMessage(errorException));

				Sinacor.Infra.Core.Logging.Logging.Log(_logData);
			}
			catch { }
           */
		}

		/// <summary>
		/// Loga a execução de uma query com erro(s)
		/// </summary>
		/// <param name="serviceMethodName">Nome completo do Servico(Namespace.Servico.Metodo)</param>
		/// <param name="startTime">Hora de inicio</param>
		/// <param name="finishTime">Hora de termino</param>
		/// <param name="query">Query processada</param>
		/// <param name="errorException">Exceção tratada</param>
		/// <param name="companyId">Usuario do banco de dados que executou a query</param>
		public static void Log(string stackTrace, DateTime startTime, DateTime finishTime, Exception errorException, int companyId, string insertCommand, string updateCommand, string deleteCommand)
		{
            //Removido temporariamente.
            /*
			_logData.LogType = LOGTYPE_QUERYEXECUTION;
			_logData.SourceClass = RetrieveServiceName(stackTrace);
			_logData.CompanyId = companyId;

			try
			{
				_logData.DetailCollection.Add("HoraInicio", startTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("HoraFim", finishTime.ToString("yyyy-MM-dd HH:mm:ss"));
				_logData.DetailCollection.Add("TempoExecucao", FormatTimeSpanToString(finishTime.Subtract(startTime)));

				if (!String.IsNullOrEmpty(insertCommand))
					_logData.DetailCollection.Add("InsertCommand", insertCommand);
				if (!String.IsNullOrEmpty(insertCommand))
					_logData.DetailCollection.Add("UpdateCommand", updateCommand);
				if (!String.IsNullOrEmpty(insertCommand))
					_logData.DetailCollection.Add("DeleteCommand", deleteCommand);

				_logData.DetailCollection.Add("Exceção", FormatExceptionMessage(errorException));

				Sinacor.Infra.Core.Logging.Logging.Log(_logData);
			}
			catch { }
            */
		}

		/// <summary>
		/// Returns a text representation of the exception.
		/// </summary>
		/// <param name="exception">The exception to be formatted.</param>
		/// <returns>Exception formatted as a text.</returns>
		static string FormatExceptionMessage(Exception exception)
		{
			StringWriter sw = null;
			using (sw = new StringWriter())
			{
				EL.TextExceptionFormatter exceptionFormatter = new EL.TextExceptionFormatter(sw, exception);
				exceptionFormatter.Format();
			}
			return sw.ToString();
		}

		/// <summary>
		/// Formata e converte um TimeSpan para uma string formatada (hh:mm:ss:milisegundos)
		/// </summary>
		/// <param name="timeSpan">TimeSpan que se deseja formatar</param>
		/// <returns>TimeSpan formatado</returns>
		static string FormatTimeSpanToString(TimeSpan timeSpan)
		{
			return String.Format("{0:hh:mm:ss.fff}", timeSpan);
		}

		/// <summary>
		/// captura o nome do serviço através do StackTrace
		/// </summary>
		/// <param name="errorStack">ErrorStack</param>
		/// <returns>Nome do serviço capturado</returns>
		static string RetrieveServiceName(string errorStack)
		{
			const string servicePattern = "Sinacor.Servico";
			const string servicePatternInfra = "Sinacor.Infra";

			string returnString = "Sinacor";

			if (errorStack.Contains(servicePattern))
			{
				returnString = errorStack.Substring(errorStack.IndexOf(servicePattern));
				return returnString.Substring(0, returnString.IndexOf('('));
			}
			else if (errorStack.Contains(servicePatternInfra))
			{
				int startIndex = 0;

				do
				{
					startIndex = errorStack.IndexOf(servicePatternInfra, startIndex);
					returnString = errorStack.Substring(startIndex);
					returnString = returnString.Substring(0, returnString.IndexOf('('));
					startIndex++;
				}
				while (returnString.Contains("Sinacor.Infra.Service.Data"));

				return returnString;
			}
			else
				return returnString;
		}
	}
}